package spring.cloud.tasks.common;

import java.io.File;
import java.lang.management.ManagementFactory;
import java.lang.management.OperatingSystemMXBean;
import java.math.RoundingMode;
import java.text.NumberFormat;

/**
 * 系统信息工具，用于采集监控指标
 */
public class MetricsUtils {

    private static final NumberFormat NUMBER_INSTANCE = NumberFormat.getNumberInstance();
    // JMX bean can be accessed externally and is meant for management tools like hyperic ( or even nagios ) - It would delegate to Runtime anyway.
    private static final OperatingSystemMXBean OPERATING_SYSTEM_MX_BEAN = ManagementFactory.getOperatingSystemMXBean();
    private static final Runtime RUNTIME = Runtime.getRuntime();

    static {
        NUMBER_INSTANCE.setMaximumFractionDigits(4);
        NUMBER_INSTANCE.setMinimumFractionDigits(4);
        NUMBER_INSTANCE.setRoundingMode(RoundingMode.HALF_UP);
        // 不按照千分位输出
        NUMBER_INSTANCE.setGroupingUsed(false);
    }

    public static Metrics getMetrics() {
        Metrics metrics = new Metrics();
        fillCPUInfo(metrics);
        fillMemoryInfo(metrics);
        fillDiskInfo(metrics);

        return metrics;
    }

    private static void fillCPUInfo(Metrics metrics) {
        metrics.setCpuProcessorNum(OPERATING_SYSTEM_MX_BEAN.getAvailableProcessors());
        metrics.setCpuLoadRatio(miniDouble(OPERATING_SYSTEM_MX_BEAN.getSystemLoadAverage()));
    }

    private static void fillMemoryInfo(Metrics metrics) {
        // JVM内存信息(maxMemory指JVM能从操作系统获取的最大内存，即-Xmx参数设置的值，totalMemory指JVM当前持久的总内存)
        long maxMemory = RUNTIME.maxMemory();
        long freeMemory = RUNTIME.freeMemory();
        long usedMemory = maxMemory - freeMemory;
        metrics.setJvmMaxMemory(bytes2GB(maxMemory));
        metrics.setJvmUsedMemory(bytes2GB(usedMemory));// 已使用内存：当前申请总量 - 当前空余量
        metrics.setJvmMemoryUsage(miniDouble((double) usedMemory / maxMemory)); // 已用内存比例
        metrics.setJvmFreeMemory(bytes2GB(freeMemory));
        metrics.setJvmFreeUsage(miniDouble((double) freeMemory / maxMemory));
    }

    private static void fillDiskInfo(Metrics metrics) {
        long free = 0;
        long total = 0;
        File[] roots = File.listRoots();
        for (File file : roots) {
            free += file.getFreeSpace();
            total += file.getTotalSpace();
        }
        metrics.setDiskTotal(bytes2GB(total));
        metrics.setDiskUsed(bytes2GB(total - free));
        metrics.setDiskUsage(miniDouble(metrics.getDiskUsed() / metrics.getDiskTotal()));
        metrics.setDiskUnUsed(bytes2GB(free));
        metrics.setDiskUnUsage(miniDouble(metrics.getDiskUnUsed() / metrics.getDiskTotal()));
    }

    private static double bytes2GB(long bytes) {
        return miniDouble(bytes / 1024.0 / 1024 / 1024);
    }

    private static double miniDouble(double origin) {
        return Double.parseDouble(NUMBER_INSTANCE.format(origin));
    }

}
